package com.zzg.lucene;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.Scorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class LuceneLighterIK {

	private static List<Passage> psgList = null;

	// 写对象
	private static IndexWriter writer = null;

	// 数据初始化
	static {
		psgList = new ArrayList<Passage>();

		// 产生一堆数据
		psgList.add(new Passage(1, "yellowcong", "717350389@qq.com", "法第三", 23, "地方萨芬阿萨德飞机哦表 ", new Date()));

		psgList.add(new Passage(2, "张三", "zhashang@qq.com", "苏东坡", 23, "UI哦傻大姐是的", new Date()));
		psgList.add(new Passage(3, "李四", "lisi@neusoft.com", "啊速度快", 23, "是的我恐怕都是反派", new Date()));
		psgList.add(new Passage(4, "王五", "wangwu@aliyun.com", "AS", 23, "撒大哥反动派搭配上开辟十大", new Date()));
		psgList.add(new Passage(5, "赵六", "zhaoliu@baidu.com", "胫腓骨", 23, "撒收到否是个坑人太好看了貌似开放购买", new Date()));
		System.out.println("-------------------------添加的数据----------------------");
		for (Passage psg : psgList) {
			System.out.println(psg.getId() + ":" + psg.getUsername() + ":" + psg.getEmail() + ":" + psg.getContent());
		}
	}
	
	// 删除全部索引
		public static void deleteAll() {
			IndexWriter writer = null;
			try {
				// 获取IndexWriter
				writer = getIndexWriter();

				// 删除所有的数据
				writer.deleteAll();

				int cnt = writer.numDocs();
				System.out.println("索引条数\t" + cnt);

				// 提交事物
				writer.commit();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				//coloseWriter(writer);
			}
		}

		// 创建索引目录
		private static String getIndexPath() {
			// 获取索引的目录
			String path = "c:\\lucene\\index";

			// 不存在就创建目录
			File file = new File(path);
			if (!file.exists()) {
				file.mkdirs();
			}
			return path;
		}

		// IndexWrite 创建
		public static IndexWriter getIndexWriter() throws Exception {
			// 创建IdnexWriter
			String path = getIndexPath();
			FSDirectory fs = FSDirectory.open(Paths.get(path));
			if(writer == null){
				// 创建IndexWriterConfig 对象
				IndexWriterConfig indexWriterConfig = new IndexWriterConfig(new IKAnalyzer());
				indexWriterConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
				// 创建writer对象
				writer = new IndexWriter(fs, indexWriterConfig);			
			}
			return writer;
		}

		// IndexReader 创建
		public static IndexReader getIndexReader() throws Exception {
			// 创建IdnexWriter
			String path = getIndexPath();
			Directory fs = FSDirectory.open(Paths.get(path));
			return DirectoryReader.open(fs);
		}

		// 索引创建
		public static void index() {
			IndexWriter writer = null;
			try {
				// 1、获取IndexWriter
				writer = getIndexWriter();
				

				// 2、建立索引
				for (Passage psg : psgList) {
					Document doc = new Document();

					// IntField 不能直接检索到，需要结合
					doc.add(new IntPoint("id", psg.getId()));

					// 用户String类型的字段的存储，StringField是只索引不分词
					doc.add(new TextField("username", psg.getUsername(), Field.Store.YES));

					// 主要对int类型的字段进行存储，需要注意的是如果需要对InfField进行排序使用SortField.Type.INT来比较，如果进范围查询或过滤，需要采用NumericRangeQuery.newIntRange()
					doc.add(new IntPoint("age", psg.getAge()));

					// 对String类型的字段进行存储，TextField和StringField的不同是TextField既索引又分词
					doc.add(new TextField("content", psg.getContent(), Field.Store.NO));

					doc.add(new StringField("keyword", psg.getKeyword(), Field.Store.YES));

					doc.add(new StringField("email", psg.getEmail(), Field.Store.YES));

					// 日期数据添加索引
					doc.add(new LongPoint("addDate", psg.getAddDate().getTime()));

					// 3、添加文档
					writer.addDocument(doc);
				}

				// 索引条数
				int cnt = writer.numDocs();
				System.out.println("索引条数\t" + cnt);

				// 提交事物
				writer.commit();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				coloseWriter(writer);
			}
		}

		// 关闭 IndexWriter
		private static void coloseWriter(IndexWriter writer) {
			try {
				if (writer != null) {
					writer.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		// 关闭 IndexReader
		public static void coloseReader(IndexReader reader) {
			try {
				if (reader != null) {
					reader.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}


	public static void main(String[] args) throws ParseException {
		// TODO Auto-generated method stub
		 // 删除 所有索引
        deleteAll();

        // 建立索引
        index();
        
        QueryParser parser = getQueryParser();
        //设定第一个* 可以匹配
        parser.setAllowLeadingWildcard(true);
        
      //精确String 类型查询
        System.out.println("-------------查询用户名为yellowcong的数据-------------");
        //精确查询，根据名称来直接
        Query query = parser.parse("username:yellowcong");
        //执行查询
        excQuery(query);
	}
	
	// 创建查询
		private static QueryParser getQueryParser() {
			QueryParser parser = new QueryParser("username", new IKAnalyzer());
			return parser;
		}

		// 执行查询
		public static void excQuery(Query query) {
			// 查询
			IndexReader reader = null;
			try {
				reader = getIndexReader();
				
				 // 1.格式化对象，设置前缀和后缀
	            SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<font color='red'>","</font>");
	            // 2.关键词对象(是highlight 的包)
	            Scorer scorer = new QueryScorer(query);
	            // 3. 高亮对象
	            Highlighter highlighter = new Highlighter(formatter, scorer);

				// 获取查询数据
				IndexSearcher searcher = new IndexSearcher(reader);

				// 检索数据
				TopDocs topDocs = searcher.search(query, 100);
				for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
					// 湖区偶
					Document doc = reader.document(scoreDoc.doc);
					  //给关键字添加高亮
	                String result = highlighter.getBestFragment(
	                        new IKAnalyzer(), 
	                        "username", //字段
	                        doc.get("username")); //高亮内容
	                System.out.println(result);
					System.out.println(doc.get("id") + ":" + doc.get("username") + ":" + doc.get("email"));
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				coloseReader(reader);
			}
		}
	
	static class Passage {
		private int id;
		private String username;
		private String email;
		private String keyword;
		private int age;
		// 这个模拟的是文章
		private String content;
		private Date addDate;

		public Passage(int id, String username, String email, String keyword, int age, String content, Date addDate) {
			super();
			this.id = id;
			this.username = username;
			this.email = email;
			this.keyword = keyword;
			this.age = age;
			this.content = content;
			this.addDate = addDate;
		}

		public int getId() {
			return id;
		}

		public void setId(int id) {
			this.id = id;
		}

		public String getUsername() {
			return username;
		}

		public void setUsername(String username) {
			this.username = username;
		}

		public String getEmail() {
			return email;
		}

		public void setEmail(String email) {
			this.email = email;
		}

		public String getKeyword() {
			return keyword;
		}

		public void setKeyword(String keyword) {
			this.keyword = keyword;
		}

		public int getAge() {
			return age;
		}

		public void setAge(int age) {
			this.age = age;
		}

		public String getContent() {
			return content;
		}

		public void setContent(String content) {
			this.content = content;
		}

		public Date getAddDate() {
			return addDate;
		}

		public void setAddDate(Date addDate) {
			this.addDate = addDate;
		}

	}
}
